package org.dromara.hm.util;

import cn.hutool.core.convert.Convert;
import lombok.RequiredArgsConstructor;
// 移除对 HmSaleOrderPickUpBo 的导入，因为它不再需要直接获取
// import org.dromara.hm.domain.bo.HmSaleOrderPickUpBo;
import org.dromara.hm.domain.bo.HmSaleOrderRefundBo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderGiftVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderPickUpVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderRefundVo;
import org.dromara.hm.domain.vo.saleOrder.HmSaleOrderVo;
import org.dromara.hm.domain.vo.saleOrder.OrderProductQuantities;
import org.dromara.hm.enums.OrderStatus;
import org.dromara.hm.enums.PickUpStatusEnum;
// 移除对 IHmSaleOrderPickUpService 的导入
// import org.dromara.hm.service.IHmSaleOrderPickUpService;
import org.dromara.hm.service.IHmProductService;
import org.dromara.hm.service.IHmSaleOrderPickUpService;
import org.dromara.hm.service.IHmSaleOrderRefundService;
import org.dromara.hm.service.IHmSupplementaryPickupRecordService;
// 移除 @Lazy 注解，因为它不再依赖 IHmSaleOrderPickUpService
// import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.DoubleStream;
/**
 * 订单产品数量计算工具类
 * 封装了订单中产品已提货、剩余提货、已回款、剩余回款等数量的计算逻辑
 *
 * @author Hzy
 * @date 2025-07-24
 */
@Component
@RequiredArgsConstructor // 此注解会为所有 final 字段生成构造器
public class OrderProductCalculator {


    private final IHmSaleOrderRefundService hmSaleOrderRefundService;
    private final IHmSupplementaryPickupRecordService supplementaryPickupRecordService;
    private final IHmProductService hmProductService; // 新增注入 IHmProductService

    /**
     * 计算指定订单中指定产品的各项数量（已提货、剩余提货、已回款、剩余回款等）。
     *
     * @param saleOrderVo 销售订单的VO对象，包含原始销售数量和金额
     * @param productId   要计算的产品ID
     * @param hmSaleOrderPickUpVos 与该订单相关的提货/回款记录列表 (由调用方提供)
     * @return 包含计算结果的 OrderProductQuantities 对象
     */
    public OrderProductQuantities calculate(
        HmSaleOrderVo saleOrderVo,
        Long productId,
        List<HmSaleOrderPickUpVo> hmSaleOrderPickUpVos) {
        OrderProductQuantities result = new OrderProductQuantities();

        // 1. 判断当前 productId 是商品产品还是赠品产品
        Boolean isCommercialProduct = hmProductService.isCommercialProduct(productId);
        Boolean isGiftProduct = hmProductService.isGiftProduct(productId);

        // 2. 获取该产品在订单中的总数量 (销售数量或赠品数量)
        BigDecimal totalProductQuantityInOrder = BigDecimal.ZERO;
        if (Boolean.TRUE.equals(isCommercialProduct)) {
            totalProductQuantityInOrder = saleOrderVo.getSaleNum(); // 主产品的销售数量
        } else if (Boolean.TRUE.equals(isGiftProduct)) {
            // 从 saleOrderVo 的 giftList 中找到对应的赠品数量
            Optional<HmSaleOrderGiftVo> giftOptional = Optional.ofNullable(saleOrderVo.getGiftList())
                .orElse(new ArrayList<>())
                .stream()
                .filter(gift -> gift.getGiftProductId() != null && gift.getGiftProductId().equals(productId))
                .findFirst();
            totalProductQuantityInOrder = giftOptional.map(HmSaleOrderGiftVo::getGiftNum).orElse(BigDecimal.ZERO);
        }
        // 如果产品既不是商品也不是赠品，或者未找到对应的赠品，则总数量为0
        if (totalProductQuantityInOrder == null) {
            totalProductQuantityInOrder = BigDecimal.ZERO;
        }


        // 3. 计算已提货数量 (来自 HmSaleOrderPickUp)
        BigDecimal pickedUpFromPickUpRecords = Optional.ofNullable(hmSaleOrderPickUpVos).orElse(new ArrayList<>()).stream()
            .filter(pickUpVo -> OrderStatus.PICK_UP.getCode().equals(pickUpVo.getPickUpType())) // 提货类型
            .filter(pickUpVo -> pickUpVo.getSaleProductId().equals(productId)) // 针对当前产品
            .map(HmSaleOrderPickUpVo::getPickUpNum) // 获取已提货数量
            .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加所有已提货数量

        // 4. 计算已通过补充提货履约的数量 (来自 HmSupplementaryPickupRecord)
        BigDecimal fulfilledBySupplementaryPickup = supplementaryPickupRecordService.getFulfilledQuantityForOriginalOrderProduct(saleOrderVo.getSaleId(), productId);
        if (fulfilledBySupplementaryPickup == null) fulfilledBySupplementaryPickup = BigDecimal.ZERO;

        // 5. 总提货退货数量 (从提货记录中退回的数量)
        BigDecimal pickedUpReturnNum = Optional.ofNullable(hmSaleOrderPickUpVos).orElse(new ArrayList<>()).stream()
            .filter(pickUpVo -> OrderStatus.PICK_UP.getCode().equals(pickUpVo.getPickUpType()))
            .filter(pickUpVo -> pickUpVo.getSaleProductId().equals(productId))
            .filter(pickUpVo -> pickUpVo.getStatus().equals(PickUpStatusEnum.RETURN.getCode())) // 退货状态
            .map(HmSaleOrderPickUpVo::getReturnNum) // 获取退货数量
            .reduce(BigDecimal.ZERO, BigDecimal::add); // 累加所有退货数量

        // 实际已提货总量 = 来自提货记录的已提货量 + 来自补充提货的已履约量 - 从提货记录中退回的数量
        BigDecimal totalPickedUpQuantity = pickedUpFromPickUpRecords
            .add(fulfilledBySupplementaryPickup)
            .subtract(pickedUpReturnNum);
        result.setTotalPickedUpQuantity(totalPickedUpQuantity);


        // 6. 过滤 pickUpType 为 0 的回款记录数据,计算商品已回款金额
        // 注意：回款通常是针对整个订单金额，而不是某个特定产品。
        // 如果您的回款记录（hm_sale_order_pick_up pick_up_type=0）中没有 saleProductId 字段来关联具体产品，
        // 那么这里的 receivedAmount 将是整个订单的回款总额。
        // 如果回款可以关联到具体产品，需要修改 hm_sale_order_pick_up 表结构。
        // 目前，假设回款是订单级别的，与特定产品无关，因此这里的 receivedAmount 仍是整个订单的回款。
        // 如果要计算某个产品的回款，需要更复杂的业务逻辑或数据结构。
        double receivedAmount = Optional.ofNullable(hmSaleOrderPickUpVos).orElse(new ArrayList<>()).stream()
            .filter(pickUpVo -> OrderStatus.RETURN_MONEY.getCode().equals(pickUpVo.getPickUpType()))
            .flatMapToDouble(pickUpVo -> DoubleStream.of(pickUpVo.getPickUpNum().doubleValue())).sum();

        // 7. 总回款退款金额 (从回款记录中退回的金额)
        double receivedReturnAmount = Optional.ofNullable(hmSaleOrderPickUpVos).orElse(new ArrayList<>()).stream()
            .filter(pickUpVo -> OrderStatus.RETURN_MONEY.getCode().equals(pickUpVo.getPickUpType()))
            .filter(pickUpVo -> pickUpVo.getStatus().equals(PickUpStatusEnum.RETURN.getCode())) // 退款状态
            .flatMapToDouble(pickUpVo -> DoubleStream.of(pickUpVo.getReturnNum().doubleValue())).sum();
        receivedAmount = receivedAmount - receivedReturnAmount; // 实际已回款金额
        result.setActualReceivedAmount(Convert.toBigDecimal(receivedAmount, BigDecimal.ZERO));


        // 8. 查询退货数量 (来自 HmSaleOrderRefund)
        HmSaleOrderRefundBo hmSaleOrderRefundBo = new HmSaleOrderRefundBo();
        hmSaleOrderRefundBo.setSaleId(saleOrderVo.getSaleId() + "");
        hmSaleOrderRefundBo.setSaleProductId(productId + ""); // 针对当前产品
        List<HmSaleOrderRefundVo> hmSaleOrderRefundVos = hmSaleOrderRefundService.queryList(hmSaleOrderRefundBo);
        BigDecimal totalRefundedQuantity = Optional.ofNullable(hmSaleOrderRefundVos).orElse(new ArrayList<>()).stream()
            .map(HmSaleOrderRefundVo::getReturnNum)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        result.setTotalRefundedQuantity(totalRefundedQuantity);

        // 9. 总退款金额 (来自 HmSaleOrderRefund)
        BigDecimal totalRefundedAmount = Optional.ofNullable(hmSaleOrderRefundVos).orElse(new ArrayList<>()).stream()
            .map(HmSaleOrderRefundVo::getRefundAmount)
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        result.setTotalRefundedAmount(totalRefundedAmount);


        // 10. 计算剩余提货数量
        // 剩余提货数量 = 产品在订单中的总数量 - 总退货数量 (已提+未提) - 实际已提货总量 (包含补充提货)
        result.setSurplusQuantity(totalProductQuantityInOrder.subtract(totalRefundedQuantity).subtract(result.getTotalPickedUpQuantity()));

        // 11. 计算剩余未回款金额 (这部分通常是订单级别的，与特定产品无关)
        // 剩余未回款金额 = 总销售金额 - 总退款金额 (来自退款单) - 实际已回款金额
        result.setRefundSurplusAmount(saleOrderVo.getSaleAmount().subtract(totalRefundedAmount).subtract(result.getActualReceivedAmount()));

        return result;
    }
}
